package srdb.migration.common;

import com.edb.jdbc2.AbstractJdbc2Statement;

import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;

import srdb.migration.MTKException;
import srdb.migration.MigrationToolkit;
import srdb.migration.Utility;
import srdb.migration.schema.metadata.Column;
import srdb.migration.schema.metadata.Constraint;
import srdb.migration.schema.metadata.ConstraintList;
import srdb.migration.schema.metadata.Schema;
import srdb.migration.schema.metadata.Table;

public abstract class MTKMetaData {
	protected Schema schema = null;
	protected Connection dbConn = null;
	protected PreparedStatement getTables;
	protected PreparedStatement parseTables;
	protected PreparedStatement getColumns;
	protected PreparedStatement getProcs;
	protected PreparedStatement getViews;
	protected PreparedStatement getTriggers;
	protected PreparedStatement getSequences;
	protected PreparedStatement getPackages;
	protected PreparedStatement getConstraints;
	protected PreparedStatement getConstraintColumns;
	protected PreparedStatement getIndexes;
	protected PreparedStatement getIndexColumns;
	protected PreparedStatement getSynonyms;
	protected PreparedStatement getAllPublicSynonyms;
	protected PreparedStatement getAllPrivateSynonyms;
	protected PreparedStatement getDBLinks;
	protected PreparedStatement getRoles;
	protected PreparedStatement getUsers;
	protected PreparedStatement getGrants;
	protected PreparedStatement getObjectTypes;
	protected PreparedStatement getRules;
	protected PreparedStatement getGroups;
	protected PreparedStatement getDomains;
	protected PreparedStatement getCustomDataTypes;
	protected String getTablesStr = null;
	protected String getColumnsStr = null;
	protected String getProcsStr = null;
	protected String getViewsStr = null;
	protected String getTriggersStr = null;
	protected String getSequencesStr = null;
	protected String getPackagesStr = null;
	protected String getConstraintsStr = null;
	protected String getConstraintColumnsStr = null;
	protected String getIndexesStr = null;
	protected String getIndexColumnsStr = null;
	protected String getSynonymStr = null;
	protected String getAllPublicSynonymStr = null;
	protected String getAllPrivateSynonymStr = null;
	protected String getDBLinksStr = null;
	protected String getRolesStr = null;
	protected String getUsersStr = null;
	protected String getGrantsStr = null;
	protected String getObjectTypesStr = null;
	protected String getRulesStr = null;
	protected String getGroupsStr = null;
	protected String getDomainsStr = null;
	protected String getCustomDataTypesStr = null;
	protected String databasename = null;

	protected String targetSchemaName = null;
	protected boolean debugFlag = false;

	protected PrintWriter schemaDDLWriter = null;
	public static String offlineMigrationSchemaDDLFilePath;
	protected String dbVersion = null;
	private DDLScriptFileFactory fileFactory;
	protected ArrayList<String> listTableIndexesDefs = new ArrayList();

	protected ArrayList<String> listTableConst = new ArrayList();

	protected int tableConstCounter = 1;

	public ArrayList<String> getListTableIndexesDefs() {
		return this.listTableIndexesDefs;
	}

	public MTKMetaData() throws Exception {
	}

	public abstract boolean supportsSynonyms();

	public abstract int getDBServerMajorVersion() throws SQLException;

	public abstract int getDBServerMinorVersion() throws SQLException;

	public abstract String getVersion() throws SQLException;

	protected abstract void initSynonymStatement(String paramString)
			throws SQLException;

	protected abstract void initAllPublicSynonymStatement() throws SQLException;

	protected abstract void initAllPrivateSynonymStatement()
			throws SQLException;

	protected abstract void initTableStatement(String paramString)
			throws SQLException;

	protected abstract void initColumnStatement() throws SQLException;

	protected abstract void initTriggerStatement(String paramString)
			throws SQLException;

	protected abstract void initViewStatement(String paramString)
			throws SQLException;

	protected abstract void initSequenceStatement(String paramString)
			throws SQLException;

	protected abstract void initProcStatement(String paramString)
			throws SQLException;

	protected abstract void initPackageStatement(String paramString)
			throws SQLException;

	protected abstract void initConstraintStatement(String paramString)
			throws SQLException;

	protected abstract void initIndexeStatement(String paramString)
			throws SQLException;

	protected abstract void initRoleStatement(String paramString)
			throws SQLException;

	protected abstract void initUserStatement(String paramString)
			throws SQLException;

	protected abstract void initGrantStatement(String paramString)
			throws SQLException;

	protected abstract void initDBLinkStatement() throws SQLException;

	protected abstract void initRulesStatement(String paramString)
			throws SQLException;

	protected abstract void initGroupsStatement(String paramString)
			throws SQLException;

	protected abstract void initDomainsStatement(String paramString)
			throws SQLException;

	protected abstract void initCustomDataTypesStatement(String paramString)
			throws SQLException;

	protected abstract void getTables() throws SQLException;

	public abstract void parseTables() throws SQLException;

	public abstract String getParseTablesMsg() throws SQLException;

	protected abstract void getProcedures() throws SQLException;

	protected abstract void getFunctions() throws SQLException;

	protected abstract void getViews() throws SQLException;

	protected abstract void getPublicSynonyms() throws SQLException;

	protected abstract void getAllPublicSynonyms() throws SQLException;

	protected abstract void getAllPrivateSynonyms() throws SQLException;

	protected abstract void getTriggers() throws SQLException;

	protected abstract void getSequences() throws SQLException;

	protected abstract void getPackages() throws SQLException;

	protected abstract void getIndexes() throws SQLException;

	protected abstract void getRoles() throws SQLException;

	protected abstract void getUsers() throws SQLException;

	protected abstract void getGrants() throws SQLException;

	protected abstract void getRules() throws SQLException;

	protected abstract void getGroups() throws SQLException;

	protected abstract void getDomains() throws SQLException;

	protected abstract void getCustomDataTypes() throws SQLException;

	public abstract String[] getSchemas() throws SQLException;

	protected abstract void getDBLinks() throws SQLException;

	protected abstract Table getTable(String paramString) throws SQLException;

	public abstract boolean isCaseSensitive(String paramString);

	protected void writeLog(String str) {
		Utility.getLogger().debug(str);
	}

	private void initPreparedStatments() throws Exception {
		try {
			initTableStatement(null);
			initColumnStatement();
			initProcStatement(null);
			initViewStatement(null);
			initTriggerStatement(null);
			initSequenceStatement(null);
			initPackageStatement(null);
			initConstraintStatement(null);
			initIndexeStatement(null);
			initSynonymStatement(null);
			initAllPublicSynonymStatement();
			initAllPrivateSynonymStatement();
			initObjectTypeStatement();
			initRulesStatement(null);
			initGroupsStatement(null);
		} catch (Exception ex) {
			throw ex;
		}
	}

	private String getCommaSepStr(String[] strArray) throws SQLException {
		StringBuffer commaSepStr = new StringBuffer();

		for (int i = 0; i < strArray.length; i++) {
			if (i > 0) {
				commaSepStr.append(",");
			}

			commaSepStr.append(strArray[i]);
		}

		return commaSepStr.toString();
	}

	private void getSchemaMetaData() throws Exception {
		initPreparedStatments();

		getTables();
		getProcedures();
		getFunctions();
		getViews();
		getTriggers();
		getSequences();
		getPackages();
		getConstraints();
		getIndexes();
		getObjectTypes();
	}

	public Schema getSchema() {
		return this.schema;
	}

	public void getTables(String[] tableNames, boolean importViewAsTable)
			throws SQLException {
		String commaSepTableNames = getCommaSepStr(tableNames);
		getTables(commaSepTableNames, importViewAsTable);
	}

	public void getTables(String commaSepTableNames, boolean importViewAsTable)
			throws SQLException {
		initTableStatement(commaSepTableNames);
		initColumnStatement();
		getTables();
	}

	public void getAllTables() throws SQLException {
		initTableStatement(null);
		initColumnStatement();
		getTables();
	}

	public void getProcedures(String[] procNames) throws SQLException {
		String commaSepProcNames = getCommaSepStr(procNames);
		getProcedures(commaSepProcNames);
	}

	public void getProcedures(String commaSepProcNames) throws SQLException {
		initProcStatement(commaSepProcNames);
		getProcedures();
	}

	public void getAllProcedures() throws SQLException {
		initProcStatement(null);
		getProcedures();
	}

	public void getFunctions(String[] funcNames) throws SQLException {
		String commaSepFuncNames = getCommaSepStr(funcNames);
		getFunctions(commaSepFuncNames);
	}

	public void getFunctions(String commaSepFuncNames) throws SQLException {
		initProcStatement(commaSepFuncNames);
		getFunctions();
	}

	public void getAllFunctions() throws SQLException {
		initProcStatement(null);
		getFunctions();
	}

	public void getViews(String[] viewNames) throws SQLException {
		String commaSepViewNames = getCommaSepStr(viewNames);
		getViews(commaSepViewNames);
	}

	public void getViews(String commaSepViewNames) throws SQLException {
		initViewStatement(commaSepViewNames);
		getViews();
	}

	public void getAllViews() throws SQLException {
		initViewStatement(null);
		getViews();
	}

	public void getPublicSynonyms(String[] tableNames) throws SQLException {
		String commaSeptabNames = getCommaSepStr(tableNames);
		getPublicSynonyms(commaSeptabNames);
	}

	public void getPublicSynonyms(String commaSepSynNames) throws SQLException {
		initSynonymStatement(commaSepSynNames);
		getPublicSynonyms();
	}

	public void getTriggers(String[] tableNames) throws SQLException {
		String commaSepTableNames = getCommaSepStr(tableNames);
		getTriggers(commaSepTableNames);
	}

	public void getTriggers(String commaSepTableNames) throws SQLException {
		initTriggerStatement(commaSepTableNames);
		getTriggers();
	}

	public void getAllTriggers() throws SQLException {
		initTriggerStatement(null);
		getTriggers();
	}

	public void getSequences(String[] sequenceNames) throws SQLException {
		String commaSepSequenceNames = getCommaSepStr(sequenceNames);
		getSequences(commaSepSequenceNames);
	}

	public void getSequences(String commaSepSequenceNames) throws SQLException {
		initSequenceStatement(commaSepSequenceNames);
		getSequences();
	}

	public void getAllSequences() throws SQLException {
		initSequenceStatement(null);
		getSequences();
	}

	public void getAllDBLinks() throws SQLException {
		initDBLinkStatement();
		getDBLinks();
	}

	public void getAllObjectTypes() throws SQLException {
		initObjectTypeStatement();
		getObjectTypes();
	}

	public void getRoles(String commaSepRoleNames) throws SQLException {
		initRoleStatement(commaSepRoleNames);
		getRoles();
	}

	public void getAllRoles() throws SQLException {
		initRoleStatement(null);
		getRoles();
	}

	public void getAllGrants(String commaSepUserNames) throws SQLException {
		initGrantStatement(commaSepUserNames);
		getGrants();
	}

	public void getAllUsers(String commaSepUserNames) throws SQLException {
		initUserStatement(commaSepUserNames);
		getUsers();
	}

	public void getAllUsers() throws SQLException {
		initUserStatement(null);
		getUsers();
	}

	public void getAllRules() throws SQLException {
		initRulesStatement(null);
		getRules();
	}

	public void getRules(String commaSepRuleNames) throws SQLException {
		initRulesStatement(commaSepRuleNames);
		getRules();
	}

	public void getAllGroups() throws SQLException {
		initGroupsStatement(null);
		getGroups();
	}

	public void getGroups(String commaSepGroupNames) throws SQLException {
		initGroupsStatement(commaSepGroupNames);
		getGroups();
	}

	public void getAllDomains() throws SQLException {
		initDomainsStatement(null);
		getDomains();
	}

	public void getDomains(String commaSepDomainNames) throws SQLException {
		initDomainsStatement(commaSepDomainNames);
		getDomains();
	}

	public void getAllCustomDataTypes() throws SQLException {
		initCustomDataTypesStatement(null);
		getCustomDataTypes();
	}

	public void getCustomDataTypes(String commaSepDomainNames)
			throws SQLException {
		initCustomDataTypesStatement(commaSepDomainNames);
		getCustomDataTypes();
	}

	protected void getConstraints() throws SQLException {
		writeLog("Getting Constraint Definitions");
		ResultSet rs = null;
		ResultSet crs = null;
		ResultSet fkrs = null;
		try {
			rs = this.getConstraints.executeQuery();

			boolean skipSysColBasedConst = false;
			String constName = "";

			while (rs.next()) {
				skipSysColBasedConst = false;

				if (rs.getString("table_name").startsWith("BIN$")) {
					continue;
				}
				boolean consNameCaseSensitive = isCaseSensitive(rs
						.getString("constraint_name"));
				String search_condition = rs.getString("search_condition");

				Table constTable = this.schema.getTable(rs
						.getString("table_name"));

				if (constTable == null) {
					constTable = getTable(rs.getString("table_name"));
					this.schema.addTable(constTable);
				}
				constName = rs.getString("constraint_name");

				Constraint constraint = new Constraint(constTable, constName,
						consNameCaseSensitive);

				if (((this instanceof srdb.migration.dbhandler.enterprisedb.MetaData))
						|| ((this instanceof srdb.migration.dbhandler.srdb.MetaData))) {
					if ((MigrationToolkit.getInstance().getTargetDBType() == MTKConstants.DATABASE_TYPE.ORACLE)
							&& (search_condition != null)
							&& (search_condition.contains("ARRAY"))) {
						Pattern p = null;
						Matcher m = null;
						p = Pattern.compile("<>");
						m = p.matcher(search_condition);
						search_condition = m.replaceAll("not in");

						p = Pattern.compile("=");
						m = p.matcher(search_condition);
						search_condition = m.replaceAll("in");

						p = Pattern.compile("ARRAY\\[");
						m = p.matcher(search_condition);
						search_condition = m.replaceAll("");

						p = Pattern.compile("\\]");
						m = p.matcher(search_condition);
						search_condition = m.replaceAll("");

						p = Pattern.compile("ALL");
						m = p.matcher(search_condition);
						search_condition = m.replaceAll("");

						p = Pattern.compile("ANY");
						m = p.matcher(search_condition);
						search_condition = m.replaceAll("");
					}

					if ((search_condition != null)
							&& (search_condition.contains("\"granted\""))) {
						Pattern p = Pattern.compile("[\"]granted[\"]");
						Matcher m = p.matcher(search_condition);
						search_condition = m.replaceAll("granted");
					}

					String constFillFactor = rs.getString("fillfactor");

					if (constFillFactor != null) {
						constraint.setFillFactor(constFillFactor);
					}

					constraint.setUpdateRule(rs.getString("update_rule"));

					constraint.setFkMatchType(rs.getString("confmatchtype"));

					constraint.setRefIntegrityTable(rs
							.getString("r_table_name"));
				}

				constraint.setType(rs.getString("constraint_type").charAt(0));
				constraint.setSearchCondition(search_condition);
				constraint.setDeleteRule(rs.getString("delete_rule"));
				setConstraintColumnsPSParams(constraint);
				crs = this.getConstraintColumns.executeQuery();

				while (crs.next()) {
					String constColumn = crs.getString("column_name");
					try {
						if (!this.schema.hasTableColumn(
								constraint.getTableName(), constColumn)) {
							skipSysColBasedConst = true;
							break;
						}
					} catch (MTKException mtke) {
						mtke.printStackTrace();
					}

					if (isCaseSensitive(constColumn)) {
						constColumn = "\"" + constColumn + "\"";
					}

					constraint.addColumn(new Column(constColumn));
				}

				crs.close();

				String refConstName = rs.getString("r_constraint_name");
				String refConstTableOwner = rs.getString("r_owner");

				if ((!rs.wasNull()) && (refConstName != null)
						&& (refConstName.length() != 0)
						&& (refConstTableOwner != null)
						&& (refConstTableOwner.length() != 0)) {
					constraint.setRefIntSchemaName(refConstTableOwner);
					setFKConstraintPSParams(constraint, refConstName);
					fkrs = this.getConstraintColumns.executeQuery();

					boolean firstTimeIteration = true;
					while (fkrs.next()) {
						if (firstTimeIteration) {
							constraint.setRefIntegrityTable(fkrs
									.getString("table_name"));
							firstTimeIteration = false;
						}
						constraint.addRefIntegrityColumn(new Column(fkrs
								.getString("column_name")));
					}

					fkrs.close();
				}

				if ((MigrationToolkit.getInstance().getSourceDBType() == MTKConstants.DATABASE_TYPE.ENTERPRISEDB)
						&& (MigrationToolkit.getInstance().getTargetDBType() == MTKConstants.DATABASE_TYPE.ORACLE)) {
					constName = constraint.getName();
					if (constName.length() > 30) {
						String tempConstName = constName.substring(0, 26);
						tempConstName = tempConstName.concat("c");
						if (this.listTableConst.contains(tempConstName)) {
							tempConstName = tempConstName.concat(""
									+ this.tableConstCounter++);
						}
						constName = tempConstName;
						this.listTableConst.add(tempConstName);
					} else {
						this.listTableConst.add(constName);
					}
					constraint.setName(constName);
				}

				if ((constraint != null) && (!skipSysColBasedConst)) {
					this.schema.addConstraint(constraint);
				}

			}

			int i = 0;
			for (int count = 1; i < this.schema.getConstraints().size(); i++) {
				Constraint cons = this.schema.getConstraints().get(i);

				if (this.schema.getTable(cons.getName()) != null)
					cons.setName(cons.getName() + "_" + count++);
			}
		} finally {
			if (fkrs != null) {
				fkrs.close();
			}

			if (crs != null) {
				crs.close();
			}

			if (rs != null)
				rs.close();
		}
	}

	protected abstract void setConstraintColumnsPSParams(
			Constraint paramConstraint) throws SQLException;

	protected void setFKConstraintPSParams(Constraint constraint,
			String refConstName) throws SQLException {
		this.getConstraintColumns
				.setString(1, constraint.getRefIntSchemaName());
		this.getConstraintColumns.setString(2, refConstName);
	}

	public void getPackages(String[] packageNames) throws SQLException {
		String commaSepPackageNames = getCommaSepStr(packageNames);
		getSequences(commaSepPackageNames);
	}

	public void getPackages(String commaSepPackageNames) throws SQLException {
		initPackageStatement(commaSepPackageNames);
		getPackages();
	}

	public void getAllPackages() throws SQLException {
		initPackageStatement(null);
		getPackages();
	}

	public void getConstraints(String[] tableNames) throws SQLException {
		String commaSepTableNames = getCommaSepStr(tableNames);
		getConstraints(commaSepTableNames);
	}

	public void getConstraints(String commaSepTableNames) throws SQLException {
		try {
			initConstraintStatement(commaSepTableNames);
			getConstraints();
		} finally {
			closeConstraintStatement();
		}
	}

	public void getAllConstraints() throws SQLException {
		try {
			initConstraintStatement(null);
			getConstraints();
		} finally {
			closeConstraintStatement();
		}
	}

	private void closeConstraintStatement() throws SQLException {
		if (this.getConstraints != null) {
			this.getConstraints.close();
		}

		if (this.getConstraintColumns != null)
			this.getConstraintColumns.close();
	}

	public void getIndexes(String[] tableNames) throws SQLException {
		String commaSepTableNames = getCommaSepStr(tableNames);
		getIndexes(commaSepTableNames);
	}

	public void getIndexes(String commaSepTableNames) throws SQLException {
		try {
			initIndexeStatement(commaSepTableNames);
			getIndexes();
		} finally {
			closeIndexStatement();
		}
	}

	public void getAllSynonyms() throws SQLException {
		initSynonymStatement(null);
		getPublicSynonyms();
	}

	public void getPublicSynonym() throws SQLException {
		initAllPublicSynonymStatement();
		getAllPublicSynonyms();
	}

	public void getPrivateSynonyms() throws SQLException {
		initAllPrivateSynonymStatement();
		getAllPrivateSynonyms();
	}

	public void getAllIndexes() throws SQLException {
		try {
			initIndexeStatement(null);
			getIndexes();
		} finally {
			closeIndexStatement();
		}
	}

	private void closeIndexStatement() throws SQLException {
		if (this.getIndexes != null) {
			this.getIndexes.close();
		}

		if (this.getIndexColumns != null)
			this.getIndexColumns.close();
	}

	public void setDebug(boolean DebugFlag) {
		this.debugFlag = DebugFlag;
	}

	public void setSchema(String schemaName, boolean loadMetaData)
			throws Exception {
		this.schema = new Schema(schemaName, isCaseSensitive(schemaName));

		if (loadMetaData)
			getSchemaMetaData();
	}

	public void addTable(String tableName) throws SQLException {
		Table table = getTable(tableName);
		if (table != null)
			this.schema.addTable(table);
	}

	public void addTables(String[] tableNames) throws SQLException {
		for (int i = 0; i < tableNames.length; i++) {
			String tableName = tableNames[i];
			if (tableName != null)
				addTable(tableName);
		}
	}

	public String getDBVersion() {
		if (this.dbVersion != null) {
			return this.dbVersion;
		}

		Statement stmt = null;
		ResultSet rs = null;
		try {
			stmt = this.dbConn.createStatement();
			rs = stmt.executeQuery("SELECT version()");

			if (rs.next())
				this.dbVersion = rs.getString(1);
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}

				if (stmt != null)
					stmt.close();
			} catch (SQLException sqle) {
			}
		}
		return this.dbVersion;
	}

	public void saveScript(String sql, MTKConstants.ObjectTypes type)
			throws IOException {
		if (this.fileFactory == null) {
			String schemaName = "";

			if (this.schema.getName() != null) {
				schemaName = this.schema.getName().toLowerCase();
			}

			this.fileFactory = DDLScriptFileFactory.getInstance(
					offlineMigrationSchemaDDLFilePath, schemaName);
		}

		PrintWriter writer = this.fileFactory.getFileWriter(type);
		writer.println();
		writer.println(sql);

		if ((type != MTKConstants.ObjectTypes.USER)
				&& (type != MTKConstants.ObjectTypes.ROLE)
				&& (type != MTKConstants.ObjectTypes.GRANT)) {
			PrintWriter masterFileWriter = this.fileFactory
					.getMasterFileWriter();
			masterFileWriter.println();
			masterFileWriter.println(sql);

			if (type == MTKConstants.ObjectTypes.SCHEMA)
				masterFileWriter
						.println(this.fileFactory.getSearchPathString());
		}
	}

	public void closeScriptWriters() {
		if (this.fileFactory != null)
			this.fileFactory.closeWriters();
	}

	public void executeScript(String sql) throws SQLException {
		Statement stmt = null;
		try {
			if (sql.compareTo("") != 0) {
				stmt = this.dbConn.createStatement();

				if (sql.split(";").length >= 2) {
					if (stmt.getClass().getPackage().getName()
							.startsWith("srdb.migration")) {
						((AbstractJdbc2Statement) stmt).executeSimpleQuery(sql);
					} else if (stmt.getClass().getPackage().getName()
							.startsWith("org.srdbsql")) {
						String[] sqlToken = sql.split("GO/");
						for (int i = 0; i < sqlToken.length; i++)
							stmt.execute(sqlToken[i]);
					}
				} else
					stmt.execute(sql);
			}
		} catch (SQLException se) {
			String msg = se.getMessage();
			Pattern p = Pattern.compile(
					".*\\s(at\\s+or)?(near\\s+(line\\s+)?(\\d+)).*", 42);
			Matcher m = p.matcher(msg);

			Pattern p2 = Pattern
					.compile(
							"[\\s]*CREATE[\\s]+(OR[\\s]+REPLACE[\\s]+)?(FUNCTION|PROCEDURE|PACKAGE|PACKAGE\\s+BODY)[\\s]+([_a-zA-Z][_a-zA-Z0-9]*|\"[^\"]+\"|'[^']+')(.*)",
							42);

			Matcher m2 = p2.matcher(sql);

			Pattern p3 = Pattern.compile("(.*)Position:(\\s)*(\\d+).*", 42);
			Matcher m3 = p3.matcher(msg);

			if ((m.matches()) && (m2.matches())) {
				try {
					String linenum = m.group(4);
					if (linenum != null) {
						int num = Integer.parseInt(linenum);

						String withoutHeader = removeProcHeader(m2.group(4));
						String[] lines = withoutHeader.split("\\n");
						if ((lines.length >= num) && (num > 0)) {
							String txt = "";
							for (int i = num - 2; i >= 0; i--) {
								if (lines[i].lastIndexOf(";") != -1) {
									if (lines[i].indexOf(";") >= lines[i]
											.length() - 1)
										break;
									txt = lines[i].substring(lines[i]
											.indexOf(";") + 1) + "\n" + txt;
									break;
								}

								txt = lines[i] + "\n" + txt;
							}

							txt = txt.trim();

							if (txt.length() == 0)
								txt = lines[(num - 1)];
							else {
								txt = txt + "\n" + lines[(num - 1)];
							}

							if (lines[(num - 1)].indexOf(";") == -1) {
								for (int i = num; i < lines.length; i++) {
									if (lines[i].indexOf(";") != -1)
										txt = txt
												+ "\n"
												+ lines[i].substring(lines[i]
														.indexOf(";"));
									else {
										txt = txt + "\n" + lines[i];
									}
								}
							}
							int wherePosition = msg.indexOf("Where");
							if (wherePosition != -1) {
								msg = msg.substring(0, wherePosition - 1)
										.trim();
								msg = msg + " " + m.group(2);
							}
							msg = msg.trim();
							throw new SQLException(msg + "\nStatement:" + txt);
						}
					}
				} catch (SQLException sqle) {
					throw sqle;
				} catch (Exception ex) {
//					throw ex;
					ex.printStackTrace();
				}
			} else if (m3.matches()) {
				String newMsg = m3.group(1);
				String position = m3.group(3);
				if ((newMsg != null) && (position != null)) {
					newMsg = newMsg.trim() + " at position " + position;
					throw new SQLException(newMsg
							+ "\n"
							+ getErrorContext(sql,
									Integer.parseInt(position.trim())));
				}
			}
			throw se;
		} finally {
			if (stmt != null)
				stmt.close();
		}
	}

	private String removeProcHeader(String src) {
		int countBraces = 0;
		int index = 0;
		do {
			char c = src.charAt(index++);
			switch (c) {
			case '(':
				countBraces++;
				break;
			case ')':
				countBraces--;
			}
		} while (countBraces != 0);

		String tmpSrc = src.toLowerCase();
		int newIndex = tmpSrc.indexOf("is", index);

		if (newIndex == -1) {
			newIndex = tmpSrc.indexOf("as", index);
		}

		if (newIndex == -1) {
			return src;
		}

		tmpSrc = src.substring(newIndex + 2);
		return tmpSrc.trim();
	}

	private String getErrorContext(String src, int position) {
		int start = 0;
		int end = 0;

		for (start = position - 1; (start >= 0) && (src.charAt(start) != ';'); start--)
			;
		for (end = position; (end < src.length()) && (src.charAt(end) != ';'); end++)
			;
		if (start == end) {
			return src;
		}

		if (start == -1) {
			start = 0;
		}

		if (end > src.length()) {
			end = src.length();
		}

		String str = src.substring(start, end);

		int newPosition = position - start;
		str = str.replaceAll("[\n]", " ") + "\n";
		str = str
				+ new Formatter().format(new StringBuilder().append("%")
						.append(newPosition).append("s").toString(),
						new Object[] { "^" });
		return str;
	}

	public boolean schemaExists(String schemaName) throws SQLException {
		boolean schemaFlag = false;
		ResultSet rs = null;
		try {
			rs = this.dbConn.getMetaData().getSchemas();
			while (rs.next()) {
				if (rs.getString("TABLE_SCHEM").equalsIgnoreCase(schemaName))
					schemaFlag = true;
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}

		return schemaFlag;
	}

	protected String removeSingleQuotes(String commaSepObjNames) {
		String value = commaSepObjNames;
		if ((value != null) && (value.length() > 0)) {
			String[] names = value.split(",");
			StringBuilder builder = new StringBuilder();

			for (int i = 0; i < names.length; i++) {
				if ((names[i].startsWith("'")) && (names[i].endsWith("'")))
					builder.append(names[i].substring(1, names[i].length() - 1));
				else {
					builder.append(names[i]);
				}
				if (i < names.length - 1) {
					builder.append(",");
				}
			}
			value = builder.toString();
		}
		return value;
	}

	public void clearConstraintsList() {
		if (this.schema != null)
			this.schema.clearConstraintsList();
	}

	public void clearIndexesList() {
		if (this.schema != null)
			this.schema.clearIndexesList();
	}

	public void dropTableConstsAndIndexes(
			MTKConstants.DATABASE_TYPE sourceDBType, Table table)
			throws SQLException {
	}

	public void dropTableConsts(MTKConstants.DATABASE_TYPE sourceDBType,
			Table table, MTKConstants.TABLE_CONSTRAINT_TYPE constType)
			throws SQLException {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	protected void initObjectTypeStatement() throws SQLException {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	protected void getObjectTypes() throws SQLException {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public abstract String getDatabaseName();
}

/*

 */